#include "stdafx.h"
#include "CollapseGUIStyle.h"

#include "Timer.h"
#include "Exception.h"
#include "Filesystem.h"

// TODO: fix "blend_modiefiers" to shifts

const Color font_color(0, 0, 0);
const Color font_color_selected(64, 64, 64);

const float button_slide_distance = 3.0f;
const float sliding_time = 0.1f;
const float slider_width = 96.0f;
const float slider_height = 7.0f;
float selector_button_size;
float switch_button_size;

const RectF mouse_source(0.0f, 0.0f, 16.0f, 16.0f);
const RectF slider_source(0.0f, 17.0f, 96.0f, 7.0f);
const RectF slider_knob_up_source(1.0f, 25.0f, 4.0f, 7.0f);
const RectF slider_knob_down_source(6.0f, 25.0f, 4.0f, 7.0f);

CollapseGUIStyle::CollapseGUIStyle(SpriteBatchPtr sprite_batch, TextureManagerPtr texture_manager, BitmapFontPtr font, uint layer)
: sprite_batch(sprite_batch), font(font), layer(layer)
{
	texture = texture_manager->loadTexture2D("collapse_gui", Filesystem::redirect("collapse_gui.png"));
	selector_button_size = font->getWidth("[");
	switch_button_size = font->getWidth("+ ");
}

CollapseGUIStyle::~CollapseGUIStyle()
{
}

bool CollapseGUIStyle::hitButton(const Vector2& pos, const std::string& text)
{
	RectF button(pos, Vector2(font->getWidth(text) + button_slide_distance, font->getHeight()));
	return button.collidePoint(mouse_pos);
}

bool CollapseGUIStyle::hitSwitch(const Vector2& pos, const std::string& text)
{
	RectF switch_(pos, Vector2(font->getWidth(text) + button_slide_distance + switch_button_size, font->getHeight()));
	return switch_.collidePoint(mouse_pos);
}

float CollapseGUIStyle::hitSlider(const Vector2& pos)
{
	RectF slider(pos, Vector2(slider_width, slider_height));
	if(!slider.collidePoint(mouse_pos))
		return -1.0f;

	return (mouse_pos.x - pos.x) / slider_width;
}

bool CollapseGUIStyle::hitSelector(const Vector2& pos, const std::vector<std::string>& selections, uint& button)
{
	uint id = GUI::hashWidget(GUI::WIDGET_SELECTOR, pos);
	if(!cache.exists(id))
	{
		WidgetState dummy;
		dummy.selector.next_shift = 0.0f;
		dummy.selector.prev_shift = 0.0f;
		dummy.selector.width = calcSelectorWidth(selections);
		cache.set(dummy, id);
	}
	float width = cache.at(id).selector.width;

	button = 0;
	RectF selector(pos, Vector2(width, font->getHeight()));
	if(!selector.collidePoint(mouse_pos))
		return false;

	/*
	RectF prev(pos, Vector2(selector_button_size, font->getHeight()));
	RectF next(pos.x + (width - selector_button_size), pos.y, selector_button_size, font->getHeight());

	// Both can't be true
	assert(!(prev.collidePoint(mouse_pos) && next.collidePoint(mouse_pos)));

	if(prev.collidePoint(mouse_pos))
		button = 1;
	if(next.collidePoint(mouse_pos))
		button = 2;
	*/
	float middle = pos.x + width / 2.0f;
	if(mouse_pos.x < middle-2.0f)
		button = 1;
	if(mouse_pos.x > middle+2.0f)
		button = 2;

	return true;
}

void CollapseGUIStyle::drawLabel(const Vector2& pos, const std::string& text)
{
	font->draw(pos, text, font_color);
}

void CollapseGUIStyle::drawButton(const Cvekas::Vector2 &pos, const std::string &text, bool mouse_over, bool pressed)
{
	
	uint id = GUI::hashWidget(GUI::WIDGET_BUTTON, pos);
	
	if(!cache.exists(id))
	{
		WidgetState dummy;
		dummy.shift = 0.0f;
		cache.set(dummy, id);
	}
	
	float& blend_modifier = cache.at(id).shift;
	
	if(mouse_over)
	{
		blend_modifier += Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier > 1.0f)
			blend_modifier = 1.0f;
	}
	else
	{
		blend_modifier -= Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier < 0.0f)
			blend_modifier = 0.0f;
	}

	Color color = Color::lerp(font_color, font_color_selected, blend_modifier);

	Vector2 text_pos(blend_modifier * blend_modifier * button_slide_distance, 0.0f);
	text_pos += pos;

	font->draw(text_pos, text, color);
}

void CollapseGUIStyle::drawSwitch(const Cvekas::Vector2 &pos, const std::string &text, bool mouse_over, bool state)
{
	
	uint id = GUI::hashWidget(GUI::WIDGET_SWITCH, pos);
	
	if(!cache.exists(id))
	{
		WidgetState dummy;
		dummy.shift = 0.0f;
		cache.set(dummy, id);
	}
	
	float& blend_modifier = cache.at(id).shift;
	
	if(mouse_over)
	{
		blend_modifier += Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier > 1.0f)
			blend_modifier = 1.0f;
	}
	else
	{
		blend_modifier -= Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier < 0.0f)
			blend_modifier = 0.0f;
	}
	
	Color color = Color::lerp(font_color, font_color_selected, blend_modifier);

	Vector2 text_pos(blend_modifier * blend_modifier * button_slide_distance, 0.0f);
	text_pos += pos;

	std::string new_text = (state ? "+ " : "- ") + text;

	font->draw(text_pos, new_text, color);
}

void CollapseGUIStyle::drawSlider(const Cvekas::Vector2 &pos, bool mouse_over, float state)
{
	uint id = GUI::hashWidget(GUI::WIDGET_SLIDER, pos);
	
	if(!cache.exists(id))
	{
		WidgetState dummy;
		dummy.shift = 0.0f;
		cache.set(dummy, id);
	}
	
	float& blend_modifier = cache.at(id).shift;
	
	if(mouse_over)
	{
		blend_modifier += Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier > 1.0f)
			blend_modifier = 1.0f;
	}
	else
	{
		blend_modifier -= Timer::getTimeScale() * (1.0f / sliding_time);
		if(blend_modifier < 0.0f)
			blend_modifier = 0.0f;
	}

	sprite_batch->draw(texture, layer+1, slider_source, pos);

	Vector2 knob_pos(pos.x + (slider_source.width - slider_knob_down_source.width) * state, pos.y);

	sprite_batch->draw(texture, layer+2, slider_knob_down_source, knob_pos, Color(255, 255, 255, int(blend_modifier * 255.0f)));
	sprite_batch->draw(texture, layer+3, slider_knob_up_source, knob_pos, Color(255, 255, 255, int(255.0f - blend_modifier * 255.0f)));
}

void CollapseGUIStyle::drawSelector(const Vector2& pos, const std::vector<std::string>& selections, uint item, 
		bool mouse_over, bool mouse_over_prev, bool mouse_over_next, bool pressed)
{
	uint id = GUI::hashWidget(GUI::WIDGET_SELECTOR, pos);
	
	if(!cache.exists(id))
	{
		WidgetState dummy;
		dummy.selector.next_shift = 0.0f;
		dummy.selector.prev_shift = 0.0f;
		dummy.selector.width = calcSelectorWidth(selections);
		cache.set(dummy, id);
	}
	
	SelectorState& state = cache.at(id).selector;

	if(mouse_over_prev)
	{
		state.prev_shift += Timer::getTimeScale() * (1.0f / sliding_time);
		if(state.prev_shift > 1.0f)
			state.prev_shift = 1.0f;
	}
	else
	{
		state.prev_shift -= Timer::getTimeScale() * (1.0f / sliding_time);
		if(state.prev_shift < 0.0f)
			state.prev_shift = 0.0f;
	}

	if(mouse_over_next)
	{
		state.next_shift += Timer::getTimeScale() * (1.0f / sliding_time);
		if(state.next_shift > 1.0f)
			state.next_shift = 1.0f;
	}
	else
	{
		state.next_shift -= Timer::getTimeScale() * (1.0f / sliding_time);
		if(state.next_shift < 0.0f)
			state.next_shift = 0.0f;
	}

	Color color_prev = Color::lerp(font_color, font_color_selected, state.prev_shift);
	Color color_next = Color::lerp(font_color, font_color_selected, state.next_shift);

	Vector2 prev_pos(-state.prev_shift * state.prev_shift * button_slide_distance, 0.0f);
	prev_pos += pos;

	Vector2 next_pos(state.next_shift * state.next_shift * button_slide_distance, 0.0f);
	next_pos += pos;
	next_pos.x += state.width - selector_button_size;

	Vector2 text_pos(pos);
	text_pos.x += (state.width - font->getWidth(selections[item])) / 2.0f;

	font->draw(prev_pos, "[", color_prev);
	font->draw(next_pos, "]", color_next);
	font->draw(text_pos, selections[item], font_color);
}

void CollapseGUIStyle::endFrame()
{
	sprite_batch->draw(texture, layer+3, RectF(0.0f, 0.0f, 16.0f, 16.0f), mouse_pos);
}

void CollapseGUIStyle::drawSimpleSlider(const Vector2& pos, float state, const Color& color)
{
	sprite_batch->draw(texture, layer+1, slider_source, pos, color);
	Vector2 knob_pos(pos.x + (slider_source.width - slider_knob_down_source.width) * state, pos.y);
	sprite_batch->draw(texture, layer+2, slider_knob_down_source, knob_pos, color);
}

float CollapseGUIStyle::calcSelectorWidth(const std::vector<std::string>& selections)
{
	// Find max text width
	float max_width = 0.0f;
	for(std::vector<std::string>::const_iterator itr = selections.begin(); itr != selections.end(); ++itr)
		max_width = max(max_width, font->getWidth(*itr));

	return max_width + selector_button_size * 2.0f;
}
